home *** CD-ROM | disk | FTP | other *** search
/ Aminet 7 / Aminet 7 - August 1995.iso / Aminet / gfx / conv / GIF_Trans.lha / GIFTrans.c < prev   
C/C++ Source or Header  |  1995-05-14  |  27KB  |  969 lines

  1. /*
  2. ** GIFtrans v1.12
  3. **
  4. ** Convert any GIF file into a GIF89a
  5. ** Allows for setting the transparent or background color, changing colors,
  6. ** adding or removing comments. Also code to analyze GIF contents.
  7. **
  8. ** Copyright (c) 24.2.94 by Andreas Ley <ley@rz.uni-karlsruhe.de>
  9. **
  10. ** Permission to use, copy, modify, and distribute this software for any
  11. ** purpose and without fee is hereby granted, provided that the above
  12. ** copyright notice appears in all copies. This software is provided "as is"
  13. ** and without any express or implied warranties.
  14. **
  15. ** This program has been tested on a HP9000/715 with HP-UX A.09.05
  16. ** In this environment, neither lint -u nor gcc -Wall produce any messages.
  17. ** It has also been compiled on AIX 3.2 and Solaris 2.3.
  18. ** If you encounter any errors or need to make any changes to port it
  19. ** to another platform, please contact me.
  20. **
  21. ** Known bugs:
  22. **    -B flag won't work if there's an Extension between the Global Color
  23. **    Table and the Image Descriptor (or Graphic Control Extension). If -V
  24. **    has been specified, a Warning Message will be displayed.
  25. **    Will be fixed in 2.0 (if ever)
  26. **    -D option may output changed data instead of original data, use
  27. **    with caution, best only with then -L option.
  28. **
  29. ** Version history
  30. **
  31. ** Version 1.12 - 17.2.95
  32. **    Incorporated dumpcomment by omerzu@quantum.de (Thomas Omerzu)
  33. **    Outputs original version if newer than GIF89a.
  34. **
  35. ** Version 1.11.2 - 14.12.94
  36. **    Incorporated OS/2 port by k.rusch@ieee.org (Klaus Johannes Rusch)
  37. **    Different rgb.txt file for OS/2, setmode replaced by freopen for
  38. **    OS/2 (SAA C) 
  39. **
  40. ** Version 1.11.1 - 11.8.94
  41. **    Allows for use of the -g option without the -B option.
  42. **
  43. ** Version 1.11 - 21.7.94
  44. **    Moved Plain Text Extension to the Extensions section where it belongs.
  45. **    Accept Unknown Extension Labels.
  46. **    Incorporated MS-DOS port by enzo@hk.net (Enzo Michelangeli).
  47. **    Added -o and -e options to redirect stdout and stderr.
  48. **    Added -D debug flag.
  49. **
  50. ** Version 1.10.2 - 22.6.94
  51. **    Support for -DRGBTXT flag.
  52. **
  53. ** Version 1.10.1 - 21.6.94
  54. **    Different rgb.txt file FreeBSD/386BSD.
  55. **
  56. ** Version 1.10 - 19.6.94
  57. **    Added -g option to change a color in the global color table.
  58. **    Added -B option to change the color for the transparent color index.
  59. **
  60. ** Version 1.9.1 - 7.6.94
  61. **    Different rgb.txt files for X11 and Open Windows.
  62. **
  63. ** Version 1.9 - 1.6.94
  64. **    Fixed a bug which caused color names to be rejected.
  65. **
  66. ** Version 1.8 - 30.5.94
  67. **    Accept #rrggbb style arguments.
  68. **    Do nothing if rgb-color not found in GIF.
  69. **
  70. ** Version 1.7 - 16.5.94
  71. **    Added -l option to only list the color table.
  72. **    Added -L option for verbose output without creating a gif.
  73. **    Added -b option to change the background color index.
  74. **    Display all matching color names for color table entries.
  75. **    Fixed a bug which caused bad color names if rgb.txt starts with
  76. **        whitespace.
  77. **    Doesn't use strdup anymore.
  78. **    Fixed =& bug on dec machines.
  79. **
  80. ** Version 1.6 - 5.4.94
  81. **    Added color names recognition.
  82. **
  83. ** Version 1.5 - 15.3.94
  84. **    Added basic verbose output to analyze GIFs.
  85. **
  86. ** Version 1.4 - 8.3.94
  87. **    Fixed off-by-one bug in Local Color table code.
  88. **    Added -c and -C options to add or remove a comment.
  89. **    Transparency is no longer the default.
  90. **
  91. ** Thanx for bug reports, ideas and fixes to
  92. **    patricka@cs.kun.nl (Patrick Atoon)
  93. **    wes@msc.edu (Wes Barris)
  94. **    pmfitzge@ingr.com (Patrick M. Fitzgerald)
  95. **    hoesel@chem.rug.nl (Frans van Hoesel)
  96. **    boardman@jerry.sal.wisc.edu (Dan Boardman)
  97. **    krweiss@chip.ucdavis.edu (Ken Weiss)
  98. **    chuck.musciano@harris.com (Chuck Musciano)
  99. **    heycke@camis.stanford.edu (Torsten Heycke)
  100. **    claw@spacsun.rice.edu (Colin Law)
  101. **    jwalker@eos.ncsu.edu (Joseph C. Walker)
  102. **    Bjorn.Borud@alkymi.unit.no (Bjorn Borud)
  103. **    Christopher.Vance@adfa.oz.au (CJS Vance)
  104. **    pederl@norway.hp.com (Peder Langlo)
  105. **    I.Rutson@bradford.ac.uk (Ian Rutson)
  106. **    Nicolas.Pioch@enst.fr (Nicolas Pioch)
  107. **    john@charles.CS.UNLV.EDU (John Kilburg)
  108. **    enzo@hk.net (Enzo Michelangeli)
  109. **    twv@hpwtwe0.cup.hp.com (Terry von Gease)
  110. **    k.rusch@ieee.org (Klaus Johannes Rusch)
  111. **    omerzu@quantum.de (Thomas Omerzu)
  112. **
  113. ** Original distribution site is
  114. **    ftp://ftp.rz.uni-karlsruhe.de/pub/net/www/tools/giftrans.c
  115. ** A man-page by knordlun@fltxa.helsinki.fi (Kai Nordlund) is at
  116. **    ftp://ftp.rz.uni-karlsruhe.de/pub/net/www/tools/giftrans.1
  117. ** To compile for MS-DOS or OS/2, you need getopt:
  118. **    ftp://ftp.rz.uni-karlsruhe.de/pub/net/www/tools/getopt.c
  119. ** MS-DOS executable can be found at
  120. **    ftp://ftp.rz.uni-karlsruhe.de/pub/net/www/tools/giftrans.exe
  121. ** OS/2 executable can be found at
  122. **    ftp://ftp.rz.uni-karlsruhe.de/pub/net/www/tools/giftrans.os2.exe
  123. ** A template rgb.txt for use with the MS-DOS version can be found at
  124. **    ftp://ftp.rz.uni-karlsruhe.de/pub/net/www/tools/rgb.txt
  125. ** Additional info can be found on
  126. **    http://melmac.corp.harris.com/transparent_images.html
  127. ** The GIF file format is documented in
  128. **    ftp://ftp.uu.net/doc/literary/obi/Standards/Graphics/Formats/gif89a.doc.Z
  129. */
  130.  
  131. #define AMIGA
  132.  
  133. #undef    X11        /* When using X Window System */
  134. #undef    OPENWIN        /* When using Open Windows */
  135. #undef    X386        /* When using XFree86 with FreeBSD/386BSD */
  136. #undef    OS2        /* When using IBM C/C++ 2.0 */
  137. #ifndef    MSDOS    /* required for TurboC 1.0 */
  138. #undef    MSDOS        /* When using Borland C (maybe MSC too) */
  139. #endif
  140.  
  141. #ifndef OS2_OR_MSDOS
  142. #ifdef OS2
  143. #define OS2_OR_MSDOS
  144. #endif /* OS2 */
  145. #ifdef MSDOS
  146. #define OS2_OR_MSDOS
  147. #endif /* MSDOS */
  148. #endif /* OS2_OR_MSDOS */
  149.  
  150. char copyright[] = "@(#)(c) Copyright 1994 by Andreas Ley (ley@rz.uni-karlsruhe.de)";
  151. char sccsid[] = "@(#)GIFtrans v1.12 - Transpose GIF files";
  152.  
  153. #ifndef RGBTXT
  154.     #ifdef X11
  155.         #define    RGBTXT    "/usr/lib/X11/rgb.txt"
  156.     #else /* X11 */
  157.         #ifdef OPENWIN
  158.             #define    RGBTXT    "/usr/openwin/lib/rgb.txt"
  159.         #else /* OPENWIN */
  160.             #ifdef X386
  161.                 #define    RGBTXT    "/usr/X386/lib/X11/rgb.txt"
  162.             #else /* X386 */
  163.                 #ifdef OS2_OR_MSDOS
  164.                     #define    RGBTXT    "rgb.txt"
  165.                 #else /* OS2_OR_MSDOS */
  166.                     #define    RGBTXT    "env:rgb.txt"
  167.                 #endif /* OS2_OR_MSDOS */
  168.             #endif /* X386 */
  169.         #endif /* OPENWIN */
  170.     #endif /* X11 */
  171. #endif /* RGBTXT */
  172.  
  173. #include <stdlib.h>
  174. #include <stdio.h>
  175. #include <string.h>
  176. #include <errno.h>
  177. #ifndef AMIGA
  178.     #ifndef OS2_OR_MSDOS
  179.         #include <unistd.h>
  180.         #include <ctype.h>
  181.         #include <sys/param.h>
  182.     #else /* OS2_OR_MSDOS */
  183.         #include <fcntl.h>
  184.         #ifdef OS2
  185.             #include <io.h>
  186.         #endif /* OS2 */
  187.         /*#include "getopt.c"*/ /*link with getopt.o instead */
  188.     #endif /* OS2_OR_MSDOS */
  189. #endif
  190.  
  191. #ifndef MAXPATHLEN
  192.     #define MAXPATHLEN 256
  193. #endif /* MAXPATHLEN */
  194.  
  195. #ifndef FALSE
  196. #define    FALSE    (0)        /* This is the naked Truth */
  197. #define    TRUE    (1)        /* and this is the Light */
  198. #endif
  199.  
  200. #define    SUCCESS    (0)
  201. #define    FAILURE    (1)
  202.  
  203. struct entry {
  204.     struct entry    *next;
  205.     char        *name;
  206.     int        red;
  207.     int        green;
  208.     int        blue;
  209.     } *root;
  210.  
  211. #define    NONE    (-1)
  212. #define    OTHER    (-2)
  213. #define    RGB    (-3)
  214.  
  215. struct color {
  216.     int        index;
  217.     int        red;
  218.     int        green;
  219.     int        blue;
  220.     } bc,tc,tn,go,gn;
  221.  
  222. static char    *image,*comment;
  223. static int    skipcomment,list,verbose,output,debug;
  224. static long int    pos;
  225.  
  226. static char    rgbtxt[] = RGBTXT, *rgb = rgbtxt;
  227. static char    true[] = "True";
  228. static char    false[] = "False";
  229.  
  230. #define    readword(buffer)    ((buffer)[0]+256*(buffer)[1])
  231. #define    readflag(buffer)    ((buffer)?true:false)
  232. #define    hex(c)            ('a'<=(c)&&(c)<='z'?(c)-'a'+10:'A'<=(c)&&(c)<='Z'?(c)-'A'+10:(c)-'0')
  233.  
  234.  
  235. void dump(adr,data,len)
  236. long int    adr;
  237. unsigned char    *data;
  238. size_t        len;
  239. {
  240.     int    i;
  241.  
  242.     while (len>0) {
  243.         (void)fprintf(stderr,"%08lx:%*s",adr,(int)((adr%16)*3+(adr%16>8?1:0)),"");
  244.         for (i=adr%16;i<16&&len>0;i++,adr++,data++,len--)
  245.             (void)fprintf(stderr,"%s%02x",i==8?"  ":" ",*data);
  246.         (void)fprintf(stderr,"\n");
  247.     }
  248. }
  249.  
  250.  
  251.  
  252. void writedata(dest,data,len)
  253. FILE        *dest;
  254. unsigned char    *data;
  255. size_t        len;
  256. {
  257.     unsigned char    size;
  258.  
  259.     while (len) {
  260.         size=len<256?len:255;
  261.         (void)fwrite((void *)&size,1,1,dest);
  262.         (void)fwrite((void *)data,(size_t)size,1,dest);
  263.         data+=size;
  264.         len-=size;
  265.     }
  266.     size=0;
  267.     (void)fwrite((void *)&size,1,1,dest);
  268. }
  269.  
  270.  
  271. void skipdata(src)
  272. FILE    *src;
  273. {
  274.     unsigned char    size,buffer[256];
  275.  
  276.     do {
  277.         pos=ftell(src);
  278.         (void)fread((void *)&size,1,1,src);
  279.         if (debug)
  280.             dump(pos,&size,1);
  281.         if (debug) {
  282.             pos=ftell(src);
  283.             (void)fread((void *)buffer,(size_t)size,1,src);
  284.             dump(pos,buffer,(size_t)size);
  285.         }
  286.         else
  287.             (void)fseek(src,(long int)size,SEEK_CUR);
  288.     } while (!feof(src)&&size>0);
  289. }
  290.  
  291.  
  292. void transblock(src,dest)
  293. FILE    *src;
  294. FILE    *dest;
  295. {
  296.     unsigned char    size,buffer[256];
  297.  
  298.     pos=ftell(src);
  299.     (void)fread((void *)&size,1,1,src);
  300.     if (debug)
  301.         dump(pos,&size,1);
  302.     if (output)
  303.         (void)fwrite((void *)&size,1,1,dest);
  304.     pos=ftell(src);
  305.     (void)fread((void *)buffer,(size_t)size,1,src);
  306.     if (debug)
  307.         dump(pos,buffer,(size_t)size);
  308.     if (output)
  309.         (void)fwrite((void *)buffer,(size_t)size,1,dest);
  310. }
  311.  
  312.  
  313. void dumpcomment(src)
  314. FILE    *src;
  315. {
  316.     unsigned char    size,buffer[256];
  317.     size_t i;
  318.  
  319.     pos=ftell(src);
  320.     (void)fread((void *)&size,1,1,src);
  321.     if (debug)
  322.         dump(pos,&size,1);
  323.     (void)fread((void *)buffer,(size_t)size,1,src);
  324.     if (debug)
  325.         dump(pos+1,buffer,(size_t)size);
  326.     for (i=0; i<(size_t)size; i++)
  327.     {
  328.         if (i%60==0)
  329.             (void)putc('\t',stderr);
  330.         if (isprint(buffer[i]))
  331.             (void)putc(buffer[i],stderr);
  332.         else
  333.             (void)fprintf(stderr,"\\%03o",buffer[i]);
  334.         if (i%60==59)
  335.             (void)putc('\n',stderr);
  336.     }
  337.     if (i%60)
  338.         (void)putc('\n',stderr);
  339.     (void)fseek(src,(long int)pos,SEEK_SET);
  340. }
  341.  
  342.  
  343. void transdata(src,dest)
  344. FILE    *src;
  345. FILE    *dest;
  346. {
  347.     unsigned char    size,buffer[256];
  348.  
  349.     do {
  350.         pos=ftell(src);
  351.         (void)fread((void *)&size,1,1,src);
  352.         if (debug)
  353.             dump(pos,&size,1);
  354.         if (output)
  355.             (void)fwrite((void *)&size,1,1,dest);
  356.         pos=ftell(src);
  357.         (void)fread((void *)buffer,(size_t)size,1,src);
  358.         if (debug)
  359.             dump(pos,buffer,(size_t)size);
  360.         if (output)
  361.             (void)fwrite((void *)buffer,(size_t)size,1,dest);
  362.     } while (!feof(src)&&size>0);
  363. }
  364.  
  365.  
  366. int giftrans(src,dest)
  367. FILE    *src;
  368. FILE    *dest;
  369. {
  370.     unsigned char    buffer[3*256],lsd[7],gct[3*256],gce[5];
  371.     unsigned int    cnt,cols,size,gct_size,gct_delay,gce_present;
  372.     struct entry    *rgbptr;
  373.  
  374.  
  375.     /* Header */
  376.     pos=ftell(src);
  377.     (void)fread((void *)buffer,6,1,src);
  378.     if (strncmp((char *)buffer,"GIF",3)) {
  379.         (void)fprintf(stderr,"No GIF file!\n");
  380.         return(1);
  381.     }
  382.     if (verbose) {
  383.         buffer[6]='\0';
  384.         (void)fprintf(stderr,"Header: \"%s\"\n",buffer);
  385.     }
  386.     if (debug)
  387.         dump(pos,buffer,6);
  388.     if (output) {
  389.         if (!strncmp((char *)buffer,"GIF87a",6))
  390.             buffer[4]='9';
  391.         (void)fwrite((void *)buffer,6,1,dest);
  392.     }
  393.  
  394.     /* Logical Screen Descriptor */
  395.     pos=ftell(src);
  396.     (void)fread((void *)lsd,7,1,src);
  397.     if (verbose) {
  398.         (void)fprintf(stderr,"Logical Screen Descriptor:\n");
  399.         (void)fprintf(stderr,"\tLogical Screen Width: %d pixels\n",readword(lsd));
  400.         (void)fprintf(stderr,"\tLogical Screen Height: %d pixels\n",readword(lsd+2));
  401.         (void)fprintf(stderr,"\tGlobal Color Table Flag: %s\n",readflag(lsd[4]&0x80));
  402.         (void)fprintf(stderr,"\tColor Resolution: %d bits\n",(lsd[4]&0x70>>4)+1);
  403.         if (lsd[4]&0x80) {
  404.             (void)fprintf(stderr,"\tSort Flag: %s\n",readflag(lsd[4]&0x8));
  405.             (void)fprintf(stderr,"\tSize of Global Color Table: %d colors\n",2<<(lsd[4]&0x7));
  406.             (void)fprintf(stderr,"\tBackground Color Index: %d\n",lsd[5]);
  407.         }
  408.         if (lsd[6])
  409.             (void)fprintf(stderr,"\tPixel Aspect Ratio: %d (Aspect Ratio %f)\n",lsd[6],((double)lsd[6]+15)/64);
  410.     }
  411.     if (debug)
  412.         dump(pos,lsd,7);
  413.  
  414.     /* Global Color Table */
  415.     gct_delay=FALSE;
  416.     if (lsd[4]&0x80) {
  417.         gct_size=2<<(lsd[4]&0x7);
  418.         pos=ftell(src);
  419.         (void)fread((void *)gct,gct_size,3,src);
  420.         if (go.index==RGB)
  421.             for(cnt=0;cnt<gct_size&&go.index==RGB;cnt++)
  422.                 if (gct[3*cnt]==go.red&&gct[3*cnt+1]==go.green&&gct[3*cnt+2]==go.blue)
  423.                     go.index=cnt;
  424.         if (go.index>=0) {
  425.             if (gn.index>=0) {
  426.                 gn.red=gct[3*gn.index];
  427.                 gn.green=gct[3*gn.index+1];
  428.                 gn.blue=gct[3*gn.index+2];
  429.             }
  430.             gct[3*go.index]=gn.red;
  431.             gct[3*go.index+1]=gn.green;
  432.             gct[3*go.index+2]=gn.blue;
  433.         }
  434.         if (bc.index==RGB)
  435.             for(cnt=0;cnt<gct_size&&bc.index==RGB;cnt++)
  436.                 if (gct[3*cnt]==bc.red&&gct[3*cnt+1]==bc.green&&gct[3*cnt+2]==bc.blue)
  437.                     bc.index=cnt;
  438.         if (bc.index>=0)
  439.             lsd[5]=bc.index;
  440.         if (tc.index==RGB)
  441.             for(cnt=0;cnt<gct_size&&tc.index==RGB;cnt++)
  442.                 if (gct[3*cnt]==tc.red&&gct[3*cnt+1]==tc.green&&gct[3*cnt+2]==tc.blue)
  443.                     tc.index=cnt;
  444.         if (tc.index==OTHER)
  445.             tc.index=lsd[5];
  446.         if (tn.index>=0) {
  447.             tn.red=gct[3*tn.index];
  448.             tn.green=gct[3*tn.index+1];
  449.             tn.blue=gct[3*tn.index+2];
  450.         }
  451.         if (tn.index!=NONE)
  452.             gct_delay=TRUE;
  453.     }
  454.     if (output)
  455.         (void)fwrite((void *)lsd,7,1,dest);
  456.     if (lsd[4]&0x80) {
  457.         if (list||verbose) {
  458.             (void)fprintf(stderr,"Global Color Table:\n");
  459.             for(cnt=0;cnt<gct_size;cnt++) {
  460.                 (void)fprintf(stderr,"\tColor %d: Red %d, Green %d, Blue %d",cnt,gct[3*cnt],gct[3*cnt+1],gct[3*cnt+2]);
  461.                 (void)fprintf(stderr,", #%02x%02x%02x",gct[3*cnt],gct[3*cnt+1],gct[3*cnt+2]);
  462.                 for (rgbptr=root,cols=0;rgbptr;rgbptr=rgbptr->next)
  463.                     if (rgbptr->red==gct[3*cnt]&&rgbptr->green==gct[3*cnt+1]&&rgbptr->blue==gct[3*cnt+2])
  464.                         (void)fprintf(stderr,"%s%s",cols++?", ":" (",rgbptr->name);
  465.                 (void)fprintf(stderr,"%s\n",cols?")":"");
  466.             }
  467.         }
  468.         if (debug)
  469.             dump(pos,gct,gct_size*3);
  470.         if (output&&(!gct_delay))
  471.             (void)fwrite((void *)gct,gct_size,3,dest);
  472.     }
  473.  
  474.     gce_present=FALSE;
  475.     do {
  476.         pos=ftell(src);
  477.         (void)fread((void *)buffer,1,1,src);
  478.         switch (buffer[0]) {
  479.         case 0x2c:    /* Image Descriptor */
  480.             if (verbose)
  481.                 (void)fprintf(stderr,"Image Descriptor:\n");
  482.             (void)fread((void *)(buffer+1),9,1,src);
  483.             /* Write Graphic Control Extension */
  484.             if (tc.index>=0||gce_present) {
  485.                 if (!gce_present) {
  486.                     gce[0]=0;
  487.                     gce[1]=0;
  488.                     gce[2]=0;
  489.                 }
  490.                 if (tc.index>=0) {
  491.                     gce[0]|=0x01;    /* Set Transparent Color Flag */
  492.                     gce[3]=tc.index;    /* Set Transparent Color Index */
  493.                 }
  494.                 else if (gce[0]&0x01)
  495.                     tc.index=gce[3];    /* Remember Transparent Color Index */
  496.                 gce[4]=0;
  497.                 if (tc.index>=0&&(!(buffer[8]&0x80))) { /* Transparent Color Flag set and no Local Color Table */
  498.                     gct[3*tc.index]=tn.red;
  499.                     gct[3*tc.index+1]=tn.green;
  500.                     gct[3*tc.index+2]=tn.blue;
  501.                 }
  502.                 if (output&&gct_delay) {
  503.                     (void)fwrite((void *)gct,gct_size,3,dest);
  504.                     gct_delay=FALSE;
  505.                 }
  506.                 if (output) {
  507.                     (void)fputs("\041\371\004",dest);
  508.                     (void)fwrite((void *)gce,5,1,dest);
  509.                 }
  510.             }
  511.             if (output&&gct_delay) {
  512.                 if (verbose)
  513.                     (void)fprintf(stderr,"Warning: Global Color Table has not been modified as no Transparent Color Index has been set\n");
  514.                 (void)fwrite((void *)gct,gct_size,3,dest);
  515.                 gct_delay=FALSE;
  516.             }
  517.             /* Write Image Descriptor */
  518.             if (verbose) {
  519.                 (void)fprintf(stderr,"\tImage Left Position: %d pixels\n",readword(buffer+1));
  520.                 (void)fprintf(stderr,"\tImage Top Position: %d pixels\n",readword(buffer+3));
  521.                 (void)fprintf(stderr,"\tImage Width: %d pixels\n",readword(buffer+5));
  522.                 (void)fprintf(stderr,"\tImage Height: %d pixels\n",readword(buffer+7));
  523.                 (void)fprintf(stderr,"\tLocal Color Table Flag: %s\n",readflag(buffer[9]&0x80));
  524.                 (void)fprintf(stderr,"\tInterlace Flag: %s\n",readflag(buffer[9]&0x40));
  525.                 if (buffer[9]&0x80) {
  526.                     (void)fprintf(stderr,"\tSort Flag: %s\n",readflag(buffer[9]&0x20));
  527.                     (void)fprintf(stderr,"\tSize of Global Color Table: %d colors\n",2<<(buffer[9]&0x7));
  528.                 }
  529.             }
  530.             if (debug)
  531.                 dump(pos,buffer,10);
  532.             if (output)
  533.                 (void)fwrite((void *)buffer,10,1,dest);
  534.             /* Local Color Table */
  535.             if (buffer[8]&0x80) {
  536.                 size=2<<(buffer[8]&0x7);
  537.                 pos=ftell(src);
  538.                 (void)fread((void *)buffer,size,3,src);
  539.                 if (verbose) {
  540.                     (void)fprintf(stderr,"Local Color Table:\n");
  541.                     for(cnt=0;cnt<size;cnt++)
  542.                         (void)fprintf(stderr,"\tColor %d: Red %d, Green %d, Blue %d\n",cnt,buffer[3*cnt],buffer[3*cnt+1],buffer[3*cnt+2]);
  543.                 }
  544.                 if (tc.index>=0) { /* Transparent Color Flag set */
  545.                     buffer[3*tc.index]=tn.red;
  546.                     buffer[3*tc.index+1]=tn.green;
  547.                     buffer[3*tc.index+2]=tn.blue;
  548.                 }
  549.                 if (debug)
  550.                     dump(pos,buffer,size*3);
  551.                 if (output)
  552.                     (void)fwrite((void *)buffer,size,3,dest);
  553.             }
  554.             /* Table Based Image Data */
  555.             pos=ftell(src);
  556.             (void)fread((void *)buffer,1,1,src);
  557.             if (verbose) {
  558.                 (void)fprintf(stderr,"Table Based Image Data:\n");
  559.                 (void)fprintf(stderr,"\tLZW Minimum Code Size: 0x%02x\n",buffer[0]);
  560.             }
  561.             if (debug)
  562.                 dump(pos,buffer,1);
  563.             if (output)
  564.                 (void)fwrite((void *)buffer,1,1,dest);
  565.             transdata(src,dest);
  566.             gce_present=FALSE;
  567.             break;
  568.         case 0x3b:    /* Trailer */
  569.             if (verbose)
  570.                 (void)fprintf(stderr,"Trailer\n");
  571.             if (debug)
  572.                 dump(pos,buffer,1);
  573.             if (comment&&*comment&&output) {
  574.                 (void)fputs("\041\376",dest);
  575.                 writedata(dest,(unsigned char *)comment,strlen(comment));
  576.             }
  577.             if (output)
  578.                 (void)fwrite((void *)buffer,1,1,dest);
  579.             break;
  580.         case 0x21:    /* Extension */
  581.             (void)fread((void *)(buffer+1),1,1,src);
  582.             switch (buffer[1]) {
  583.             case 0x01:    /* Plain Text Extension */
  584.                 if (output&&gct_delay) {
  585.                     if (verbose)
  586.                         (void)fprintf(stderr,"Warning: Global Color Table has not been modified due to a Plain Text Extension\n");
  587.                     (void)fwrite((void *)gct,gct_size,3,dest);
  588.                     gct_delay=FALSE;
  589.                 }
  590.                 if (verbose)
  591.                     (void)fprintf(stderr,"Plain Text Extension\n");
  592.                 if (debug)
  593.                     dump(pos,buffer,2);
  594.                 if (output)
  595.                     (void)fwrite((void *)buffer,2,1,dest);
  596.                 transblock(src,dest);
  597.                 transdata(src,dest);
  598.                 break;
  599.             case 0xf9:    /* Graphic Control Extension */
  600.                 if (verbose)
  601.                     (void)fprintf(stderr,"Graphic Control Extension:\n");
  602.                 (void)fread((void *)(buffer+2),1,1,src);
  603.                 size=buffer[2];
  604.                 (void)fread((void *)gce,size,1,src);
  605.                 if (verbose) {
  606.                     (void)fprintf(stderr,"\tDisposal Method: %d ",gce[0]&0x1c>>2);
  607.                     switch (gce[0]&0x1c>>2) {
  608.                     case 0:
  609.                         (void)fprintf(stderr,"(no disposal specified)\n");
  610.                         break;
  611.                     case 1:
  612.                         (void)fprintf(stderr,"(do not dispose)\n");
  613.                         break;
  614.                     case 2:
  615.                         (void)fprintf(stderr,"(restore to background color)\n");
  616.                         break;
  617.                     case 3:
  618.                         (void)fprintf(stderr,"(restore to previous)\n");
  619.                         break;
  620.                     default:
  621.                         (void)fprintf(stderr,"(to be defined)\n");
  622.                     }
  623.                     (void)fprintf(stderr,"\tUser Input Flag: %s\n",readflag(gce[0]&0x2));
  624.                     (void)fprintf(stderr,"\tTransparent Color Flag: %s\n",readflag(gce[0]&0x1));
  625.                     (void)fprintf(stderr,"\tDelay Time: %d\n",readword(gce+1));
  626.                     if (gce[0]&0x1)
  627.                         (void)fprintf(stderr,"\tTransparent Color Index: %d\n",gce[3]);
  628.                 }
  629.                 if (debug) {
  630.                     dump(pos,buffer,3);
  631.                     dump(pos+3,gce,size);
  632.                 }
  633.                 pos=ftell(src);
  634.                 (void)fread((void *)buffer,1,1,src);
  635.                 if (debug)
  636.                     dump(pos,buffer,1);
  637.                 gce_present=TRUE;
  638.                 break;
  639.             case 0xfe:    /* Comment Extension */
  640.                 if (verbose)
  641.                 {
  642.                     (void)fprintf(stderr,"Comment Extension\n");
  643.                     dumpcomment(src);
  644.                 }
  645.                 if (debug)
  646.                     dump(pos,buffer,2);
  647.                 if (skipcomment)
  648.                     skipdata(src);
  649.                 else {
  650.                     if (output&&gct_delay) {
  651.                         if (verbose)
  652.                             (void)fprintf(stderr,"Warning: Global Color Table has not been modified due to a Comment Extension\n");
  653.                         (void)fwrite((void *)gct,gct_size,3,dest);
  654.                         gct_delay=FALSE;
  655.                     }
  656.                     if (output)
  657.                         (void)fwrite((void *)buffer,2,1,dest);
  658.                     transdata(src,dest);
  659.                 }
  660.                 break;
  661.             case 0xff:    /* Application Extension */
  662.                 if (output&&gct_delay) {
  663.                     if (verbose)
  664.                         (void)fprintf(stderr,"Warning: Global Color Table has not been modified due to a Application Extension\n");
  665.                     (void)fwrite((void *)gct,gct_size,3,dest);
  666.                     gct_delay=FALSE;
  667.                 }
  668.                 if (verbose)
  669.                     (void)fprintf(stderr,"Application Extension\n");
  670.                 if (debug)
  671.                     dump(pos,buffer,2);
  672.                 if (output)
  673.                     (void)fwrite((void *)buffer,2,1,dest);
  674.                 transblock(src,dest);
  675.                 transdata(src,dest);
  676.                 break;
  677.             default:
  678.                 if (output&&gct_delay) {
  679.                     if (verbose)
  680.                         (void)fprintf(stderr,"Warning: Global Color Table has not been modified due to an unknown Extension\n");
  681.                     (void)fwrite((void *)gct,gct_size,3,dest);
  682.                     gct_delay=FALSE;
  683.                 }
  684.                 if (verbose)
  685.                     (void)fprintf(stderr,"Unknown label: 0x%02x\n",buffer[1]);
  686.                 if (debug)
  687.                     dump(pos,buffer,2);
  688.                 if (output)
  689.                     (void)fwrite((void *)buffer,2,1,dest);
  690.                 transblock(src,dest);
  691.                 transdata(src,dest);
  692.                 break;
  693.             }
  694.             break;
  695.         default:
  696.             (void)fprintf(stderr,"0x%08lx: Unknown extension 0x%02x!\n",ftell(src)-1,buffer[0]);
  697.             if (debug)
  698.                 dump(pos,buffer,1);
  699.             return(1);
  700.         }
  701.     } while (buffer[0]!=0x3b&&!feof(src));
  702.     return(buffer[0]==0x3b?SUCCESS:FAILURE);
  703. }
  704.  
  705.  
  706.  
  707. int getindex(c,arg)
  708. struct color    *c;
  709. char    *arg;
  710. {
  711.     struct entry    *ptr;
  712.  
  713.     if ('0'<=*arg&&*arg<='9')
  714.         c->index=atoi(arg);
  715.     else if (*arg=='#') {
  716.         if (strlen(arg)==4) {
  717.             c->index=RGB;
  718.             c->red=hex(arg[1])<<4;
  719.             c->green=hex(arg[2])<<4;
  720.             c->blue=hex(arg[3])<<4;
  721.         }
  722.         else if (strlen(arg)==7) {
  723.             c->index=RGB;
  724.             c->red=(hex(arg[1])<<4)+hex(arg[2]);
  725.             c->green=(hex(arg[3])<<4)+hex(arg[4]);
  726.             c->blue=(hex(arg[5])<<4)+hex(arg[6]);
  727.         }
  728.         else {
  729.             (void)fprintf(stderr,"%s: illegal color specification: %s\n",image,arg);
  730.             return(FAILURE);
  731.         }
  732.     }
  733.     else {
  734.         for (ptr=root;ptr&&c->index!=RGB;ptr=ptr->next)
  735.             if (!strcmp(ptr->name,arg)) {
  736.                 c->index=RGB;
  737.                 c->red=ptr->red;
  738.                 c->green=ptr->green;
  739.                 c->blue=ptr->blue;
  740.             }
  741.         if (c->index!=RGB) {
  742.             (void)fprintf(stderr,"%s: no such color: %s\n",image,arg);
  743.             return(FAILURE);
  744.         }
  745.     }
  746.     return(SUCCESS);
  747. }
  748.  
  749.  
  750.  
  751. void usage()
  752. {
  753.     (void)fprintf(stderr,"Usage: %s [-t color|-T] [-B color] [-b color] [-g oldcolor=newcolor] [-c comment|-C] [-l|-L|-V] [-o filename] [-e filename] [filename]\n",image);
  754.     (void)fprintf(stderr,"Convert any GIF file into a GIF89a, with the folloing changes possible:\n");
  755.     (void)fprintf(stderr,"-t Specify the transparent color\n");
  756.     (void)fprintf(stderr,"-T Index of the transparent color is the background color index\n");
  757.     (void)fprintf(stderr,"-B Specify the transparent color's new value\n");
  758.     (void)fprintf(stderr,"-b Specify the background color\n");
  759.     (void)fprintf(stderr,"-g Change a color in the global color table\n");
  760.     (void)fprintf(stderr,"-c Add a comment\n");
  761.     (void)fprintf(stderr,"-C Remove old comment\n");
  762.     (void)fprintf(stderr,"-l Only list the color table\n");
  763.     (void)fprintf(stderr,"-L Verbose output of GIFs contents\n");
  764.     (void)fprintf(stderr,"-V Verbose output while converting\n");
  765.     (void)fprintf(stderr,"-o Redirect stdout to a file\n");
  766.     (void)fprintf(stderr,"-e Redirect stderr to a file\n");
  767.     if (*rgb)
  768.         (void)fprintf(stderr,"Colors may be specified as index, as rgb.txt entry or in the #rrggbb form.\n");
  769.     else
  770.         (void)fprintf(stderr,"Colors may be specified as index or in the #rrggbb form.\n");
  771.     exit(1);
  772. }
  773.  
  774.  
  775. int main(argc,argv)
  776. int    argc;
  777. char    *argv[];
  778. {
  779.     int        c;
  780.     extern char    *optarg;
  781.     extern int    optind;
  782.     char        error[2*MAXPATHLEN+14],line[BUFSIZ],*ptr,*nptr,*oname,*ename;
  783.     struct entry    **next;
  784.     FILE        *src;
  785.     int        stat;
  786.  
  787. #ifdef OS2
  788.     ptr=getenv("XFILES");
  789.     if (ptr) {
  790.         rgb=(char *)malloc(strlen(ptr)+strlen(rgbtxt)+2);
  791.         (void)strcpy(rgb,ptr);
  792.         (void)strcat(rgb,"\\");
  793.         (void)strcat(rgb,rgbtxt);
  794.     }
  795. #endif /* OS2 */
  796.  
  797.     image=argv[0];
  798.     root=NULL;
  799.     if (*rgb)
  800.         if ((src=fopen(rgb,"r"))!=NULL) {
  801.             next= &root;
  802.             while (fgets(line,sizeof(line),src)) {
  803.                 *next=(struct entry *)malloc(sizeof(struct entry));
  804.                 for (ptr=line;strchr(" \t",*ptr);ptr++);
  805.                 for (nptr=ptr;!strchr(" \t",*ptr);ptr++);
  806.                 *ptr++='\0';
  807.                 (*next)->red=atoi(nptr);
  808.                 for (;strchr(" \t",*ptr);ptr++);
  809.                 for (nptr=ptr;!strchr(" \t",*ptr);ptr++);
  810.                 *ptr++='\0';
  811.                 (*next)->green=atoi(nptr);
  812.                 for (;strchr(" \t",*ptr);ptr++);
  813.                 for (nptr=ptr;!strchr(" \t",*ptr);ptr++);
  814.                 *ptr++='\0';
  815.                 (*next)->blue=atoi(nptr);
  816.                 for (;strchr(" \t",*ptr);ptr++);
  817.                 for (nptr=ptr;!strchr(" \t\r\n",*ptr);ptr++);
  818.                 *ptr='\0';
  819.                 (void)strcpy((*next)->name=(char *)malloc(strlen(nptr)+1),nptr);
  820.                 (*next)->next=NULL;
  821.                 next= &(*next)->next;
  822.             }
  823.             (void)fclose(src);
  824.         }
  825.         else {
  826. #ifndef AMIGA
  827.     #ifndef OS2_OR_MSDOS
  828.                 (void)sprintf(error,"%s: cannot open %s",image,rgb);
  829.                 perror(error);
  830.                 return(FAILURE);
  831.     #else /* OS2_OR_MSDOS */
  832.                 *rgb='\0';
  833.     #endif
  834. #endif
  835.         }
  836.  
  837.     bc.index=NONE;
  838.     tc.index=NONE;
  839.     tn.index=NONE;
  840.     go.index=NONE;
  841.     gn.index=NONE;
  842.     comment=NULL;
  843.     skipcomment=FALSE;
  844.     verbose=FALSE;
  845.     output=TRUE;
  846.     debug=FALSE;
  847.     oname=NULL;
  848.     ename=NULL;
  849.     while ((c=getopt(argc,argv,"t:TB:b:g:c:ClLVDo:e:vh?")) != EOF)
  850.         switch ((char)c) {
  851.         case 'b':
  852.             if (getindex(&bc,optarg))
  853.                 return(FAILURE);
  854.             break;
  855.         case 't':
  856.             if (getindex(&tc,optarg))
  857.                 return(FAILURE);
  858.             break;
  859.         case 'T':
  860.             tc.index=OTHER;
  861.             break;
  862.         case 'B':
  863.             if (getindex(&tn,optarg))
  864.                 return(FAILURE);
  865.             break;
  866.         case 'g':
  867.             if ((ptr=strchr(optarg,'='))!=NULL) {
  868.                 *ptr++='\0';
  869.                 if (getindex(&go,optarg))
  870.                     return(FAILURE);
  871.                 if (getindex(&gn,ptr))
  872.                     return(FAILURE);
  873.             }
  874.             else
  875.                 usage();
  876.             break;
  877.         case 'c':
  878.             comment=optarg;
  879.             break;
  880.         case 'C':
  881.             skipcomment=TRUE;
  882.             break;
  883.         case 'l':
  884.             list=TRUE;
  885.             output=FALSE;
  886.             break;
  887.         case 'L':
  888.             verbose=TRUE;
  889.             output=FALSE;
  890.             break;
  891.         case 'V':
  892.             verbose=TRUE;
  893.             break;
  894.         case 'D':
  895.             debug=TRUE;
  896.             break;
  897.         case 'o':
  898.             oname=optarg;
  899.             break;
  900.         case 'e':
  901.             ename=optarg;
  902.             break;
  903.         case 'v':
  904.             (void)fprintf(stderr,"%s\n",sccsid+4);
  905.             (void)fprintf(stderr,"%s\n",copyright+4);
  906.             return(0);
  907.         case 'h':
  908.             (void)fprintf(stderr,"%s\n",sccsid+4);
  909.             (void)fprintf(stderr,"%s\n",copyright+4);
  910.         case '?':
  911.             usage();
  912.         }
  913.     if (optind+1<argc||(bc.index==NONE&&tc.index==NONE&&tn.index==NONE&&gn.index==NONE&&comment==NULL&&!skipcomment&&!list&&!verbose))
  914.         usage();
  915.  
  916.     if (oname&&freopen(oname,"wb",stdout)==NULL) {
  917.         (void)sprintf(error,"%s: cannot open %s",image,oname);
  918.         perror(error);
  919.         return(FAILURE);
  920.     }
  921.  
  922.     if (ename&&freopen(ename,"wb",stderr)==NULL) {
  923.         (void)sprintf(error,"%s: cannot open %s",image,ename);
  924.         perror(error);
  925.         return(FAILURE);
  926.     }
  927.  
  928. #ifdef OS2_OR_MSDOS
  929.     #ifdef MSDOS
  930.         if(oname==NULL&&(stdout->flags&_F_TERM)==0&&setmode(fileno(stdout),O_BINARY)!=0) {
  931.     #endif
  932.     #ifdef OS2
  933.         if(oname==NULL&&!freopen("", "wb", stdout)) {
  934.     #endif
  935.             (void)fprintf(stderr,"%s: can't set stdout's mode to binary\n",image);
  936.             exit(2);
  937.         }
  938.     #ifdef MSDOS
  939.         if(optind==argc&&(stdin->flags&_F_TERM)==0&&setmode(fileno(stdin),O_BINARY)) {
  940.     #endif
  941.     #ifdef OS2
  942.         if(optind==argc&&!freopen("", "rb", stdin)) {
  943.     #endif
  944.             (void)fprintf(stderr,"%s: can't set stdin's mode to binary\n",image);
  945.             exit(2);
  946.         }
  947. #endif
  948.  
  949.     if (optind<argc)
  950.         if (strcmp(argv[optind],"-"))
  951.             if ((src=fopen(argv[optind],"rb"))!=NULL) {
  952.                 stat=giftrans(src,stdout);
  953.                 (void)fclose(src);
  954.             }
  955.             else {
  956.                 (void)sprintf(error,"%s: cannot open %s",image,argv[optind]);
  957.                 perror(error);
  958.                 return(FAILURE);
  959.             }
  960.         else
  961.             stat=giftrans(stdin,stdout);
  962.     else
  963.         stat=giftrans(stdin,stdout);
  964.  
  965.     (void)fclose(stdout);
  966.     (void)fclose(stderr);
  967.     return(stat);
  968. }
  969.